import { ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { AuthGuard } from "@nestjs/passport";
import { TokenService } from "../service/token.service";
import { isNil } from 'lodash'
import { ExtractJwt } from "passport-jwt";
import { FastifyReply as Response } from 'fastify';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
    constructor(
        protected reflector: Reflector,
        protected tokenService: TokenService
    ) {
        super()
    }
    async canActivate(context: ExecutionContext) {
        const request = this.getRequest(context);
        const response = this.getResponse(context);

        //从header上获取 jsonwebtoken
        const requestToken = ExtractJwt.fromAuthHeaderAsBearerToken()(request)
        if (isNil(requestToken)) return false
        const accessToken = isNil(requestToken) ? undefined : await this.tokenService.checkAccessToken(requestToken)
        //如果为undefined
        if (isNil(accessToken)) throw new UnauthorizedException()
        try {
            const result = await super.canActivate(context)
            return result as boolean
        } catch (error) {
            //尝试刷新 refreshToken 刷新token
            if (!isNil(accessToken)){
                const token=await this.tokenService.refreshToken(accessToken,response)

                if(!isNil(token))return false
                if(token.accessToken){
                    request.headers.authorization= `Bearer ${token.accessToken.value}`;
                }
                //刷新失败 则再次抛出认证失败
                const result=await super.canActivate(context)
                return result as boolean

            }
            //刷新成功则给请求头更换新的token

            //并给 响应头添加新的token 和refreshtoken

        }

    }
    handleRequest(err:any,user:any,_info:Error){
        if(err||!user){
            throw err ||new UnauthorizedException()
        }
        return user
    }



    protected getResponse(context: ExecutionContext) {
        return context.switchToHttp().getResponse()
    }
    protected getRequest(context: ExecutionContext) {
        return context.switchToHttp().getRequest()
    }

}